package com.motu.monstercity.server.game.logic;

import com.motu.monstercity.module.common.network.ResponseUtils;
import com.motu.monstercity.module.common.redis.RedisKey;
import com.motu.monstercity.protocol.CmdEnum;
import com.motu.monstercity.protocol.Common.PBUserData;
import com.motu.monstercity.protocol.CsGameSystem;
import com.motu.monstercity.protocol.CsGameSystem.CSGameSystemRedPointResponse;
import com.motu.monstercity.server.game.base.CommonUtils;
import com.motu.monstercity.server.game.base.ProtoDataUtils;
import com.motu.monstercity.server.game.commondata.act.ActConstant;
import com.motu.monstercity.server.game.commondata.act.ActTask;
import com.motu.monstercity.server.game.commondata.maintask.*;
import com.motu.monstercity.server.game.commondata.system.SystemConstant;
import com.motu.monstercity.server.game.commondata.system.UserExp;
import com.motu.monstercity.server.game.commondata.worldboss.WorldBossTask;
import com.motu.monstercity.server.game.log.LogType;
import com.motu.monstercity.server.game.userdata.*;
import com.motu.monstercity.server.game.verticle.MainVerticle;
import com.motu.vertx.module.utility.redis.RedisTools;
import com.motu.vertx.module.utility.toolset.ErrorWord;
import com.motu.vertx.module.utility.toolset.TimeUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.User;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class MainTaskManager extends MainTaskUserData{
    // 初始化 下发主线任务相关的用户数据
    public static void loadInitUserData(PBUserData.Builder pbUserData, UserInfo userInfo) {
        long userId = userInfo.getId();


        for (UserTaskValue userTaskValue : getUserTaskValueList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userTaskValue, true);
        }
        for (UserMainTask userMainTask : getUserMainTaskList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userMainTask, true);
        }
        for (UserAchieve userAchieve : getUserAchieveList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userAchieve, true);
        }
        for (UserCityTaskReward userCityTaskReward : getUserCityTaskRewardList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userCityTaskReward, true);
        }
        for (UserDayTask userDayTask : getUserDayTaskList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userDayTask, true);
        }
        for (UserHonor userHonor : getUserHonorList(userId)) {
            ProtoDataUtils.updatePBUserData(pbUserData, userHonor, true);
        }
        for (ServerHonor serverHonor : getServerHonorList(userInfo.getServerId())) {
            ProtoDataUtils.updatePBUserData(pbUserData, serverHonor, true);
        }
        UserUnion userUnion = UnionManager.getUserUnion(userId);
        if (userUnion.getUnionId() > 0) {
            for (UnionHonor unionHonor : getUnionHonorList(userUnion.getUnionId())) {
                ProtoDataUtils.updatePBUserData(pbUserData, unionHonor, true);
            }
        }
    }

    // 更新主线任务,成就,日常任务的进度, 增量
    public static void addTaskProgress(PBUserData.Builder pbUserData, UserInfo userInfo, int taskType, long addValue, Object... params) {
        int param = 0;
        if (params.length == 1) {
            param = Integer.parseInt(String.valueOf(params[0]));// 参数
        }
        boolean isAdd = true;
        updateUserDayTask(pbUserData, userInfo, taskType, (int)addValue, isAdd);// 日常任务
        updateUserTaskValue(pbUserData, userInfo, taskType, addValue, param, isAdd);// 更新主线任务和成就,城市升级任务的进度,并下发给客户端
        ActDaysManager.updateTask(pbUserData, userInfo, taskType, addValue, param, isAdd);
        FloristManager.updateTask(pbUserData, userInfo, taskType, addValue, param, isAdd);
        ActConventionManager.updateTask(pbUserData, userInfo, taskType, addValue, param, isAdd);
        UnionMobileManager.updateTask(pbUserData, userInfo, taskType, addValue, param, isAdd); // 更新联盟总动员的任务进度
    }

    // 更新主线任务,成就,日常任务的进度, 全量覆盖更新
    public static void updateTaskProgress(PBUserData.Builder pbUserData, UserInfo userInfo, int taskType, long num, Object... params) {
        int param = 0;
        if (params.length == 1) {
            param = Integer.parseInt(String.valueOf(params[0]));// 参数
        }
        boolean isAdd = false;
        updateUserDayTask(pbUserData, userInfo, taskType, (int)num, isAdd);// 日常任务
        updateUserTaskValue(pbUserData, userInfo, taskType, num, param, isAdd);// 更新主线任务和成就,城市升级任务的进度,并下发给客户端
        ActDaysManager.updateTask(pbUserData, userInfo, taskType, num, param, isAdd);
        FloristManager.updateTask(pbUserData, userInfo, taskType, num, param, isAdd);
        ActConventionManager.updateTask(pbUserData, userInfo, taskType, num, param, isAdd);
        UnionMobileManager.updateTask(pbUserData, userInfo, taskType, num, param, isAdd); // 更新联盟总动员的任务进度
    }


    // 更新玩家的个人荣誉,并下发给客户端
    public static void updateUserHonor(PBUserData.Builder pbUserData, UserInfo userInfo, int honorType, int num, boolean isAdd) {
        HonorReward honorReward = getMaxHonorReward(honorType);
        if (honorReward == null) {
            return;// 未配置对应的荣誉
        }
        long userId = userInfo.getId();
        UserHonor userHonor = getUserHonor(userId, honorType);
        if (userHonor == null) {
            userHonor = new UserHonor(userId, honorType);
            userHonor.putNum(num);
            userHonor.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userHonor, true);
        } else {
            if (userHonor.getNum() >= honorReward.getNum()) {
                return;// 已达到最大值了，不需要再更新
            }
            if (isAdd) {
                userHonor.addNum(num);
            } else {
                if (num <= userHonor.getNum())  {
                    return;
                } else {
                    userHonor.putNum(num);
                }
            }
            userHonor.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userHonor);
        }
    }

    // 更新全服的成就,并下发给客户端
    public static void updateServerHonor(PBUserData.Builder pbUserData, UserInfo userInfo, int honorType, long num) {
        List<HonorReward> list = new ArrayList<>();
        for (HonorReward honorReward : getHonorRewardMap().values()) {
            if (honorReward.getHonorType() == honorType) {
                if (num >= honorReward.getNum()) {
                    list.add(honorReward);
                }
            }
        }

        // 按num 降序排列
        List<HonorReward> listNew = list.stream().sorted(Comparator.comparingLong(HonorReward::getNum).reversed()).collect(Collectors.toList());
        boolean isPush = false;// 进行全服推送,告诉所有玩家有新的荣誉达成了
        for (HonorReward honorReward : listNew) {
            String lockKey = RedisKey.getServerHonorKey(userInfo.getServerId(), honorReward.takeHonorId());
            boolean init = Future.await(RedisTools.setnx(lockKey, "1"));
            if (init) {
                try {
                    ServerHonor serverHonor = getServerHonor(userInfo.getServerId(), honorReward.takeHonorId());
                    if (serverHonor == null) {// 还没有人达成
                        serverHonor = new ServerHonor();
                        serverHonor.putServerId(userInfo.getServerId());
                        serverHonor.putHonorId(honorReward.takeHonorId());
                        serverHonor.putUserId(userInfo.getId());
                        serverHonor.doCreate();
                        isPush = true;
                    } else {
                        break;// 更小的数值不用再判断,减少次数
                    }
                } finally {
                    Future.await(RedisTools.del(lockKey));// 释放锁
                }
            }
        }

        // 进行全服推送,告诉所有玩家有新的荣誉达成了
        if (isPush)  {
            CSGameSystemRedPointResponse.Builder builder = CSGameSystemRedPointResponse.newBuilder();
            builder.setPromptType(SystemConstant.RED_POINT_TYPE_HONOR);
            CsGameSystem.RedPoint_Honor.Builder redPoint = CsGameSystem.RedPoint_Honor.newBuilder();
            redPoint.addServerHonor(honorType);
            builder.setHonor(redPoint);
            BoardcastManager.publicRedPointAllUser(userInfo, builder);
        }
    }

    // 更新玩家的个人荣誉,并下发给客户端
    public static void updateUnionHonor(PBUserData.Builder pbUserData, long unionId, int honorType, int num, boolean isAdd) {
        HonorReward honorReward = getMaxHonorReward(honorType);
        if (honorReward == null) {
            return;// 未配置对应的荣誉
        }

        String lockKey = RedisKey.getUnionHonorKey(unionId, honorType);
        boolean init = Future.await(RedisTools.setnx(lockKey, "1"));
        if (init) {
            try {
                UnionHonor unionHonor = getUnionHonor(unionId, honorType);
                if (unionHonor == null) {
                    unionHonor = new UnionHonor(unionId, honorType);
                    unionHonor.putNum(num);
                    unionHonor.doCreate();
                    ProtoDataUtils.updatePBUserData(pbUserData, unionHonor, true);
                } else {
                    if (unionHonor.getNum() >= honorReward.getNum()) {
                        return;// 已达到最大值了，不需要再更新
                    }
                    if (isAdd) {
                        unionHonor.addNum(num);
                    } else {
                        if (num <= unionHonor.getNum())  {
                            return;
                        } else {
                            unionHonor.putNum(num);
                        }
                    }
                    unionHonor.update();
                    ProtoDataUtils.updatePBUserData(pbUserData, unionHonor);
                }
            } finally {
                Future.await(RedisTools.del(lockKey));// 释放锁
            }
        }

    }

    // 更新日常任务进度,并下发给客户端
    private static void updateUserDayTask(PBUserData.Builder pbUserData, UserInfo userInfo, int taskType, int num, boolean isAdd) {
        TaskDay dayTask = getMaxTaskDayByTaskType(taskType);// 获取需要num最大的这条记录
        if (dayTask == null) {
            return;// 未配置对应的日常任务
        }
        long userId = userInfo.getId();
        UserDayTask userDayTask = getUserDayTask(userId, taskType);
        if (userDayTask == null) {
            userDayTask = new UserDayTask();
            userDayTask.putUserId(userId);
            userDayTask.putTaskId(taskType);
            userDayTask.putNum(num);
            userDayTask.putResetTime(TimeUtils.getCurTime());
            userDayTask.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userDayTask, true);
        } else {
            if (userDayTask.getNum() >= dayTask.getNum()) {
                return;// 已经达到最大值了，不需要再更新
            }
            if (isAdd) {
                userDayTask.addNum(num);
            } else {
                if (num <= userDayTask.getNum())  {
                    return;
                } else {
                    userDayTask.putNum(num);
                }
            }
            userDayTask.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userDayTask);
        }
    }

    // 更新主线任务和成就,城市升级任务的进度,并下发给客户端
    public static void updateUserTaskValue(PBUserData.Builder pbUserData, UserInfo userInfo, int taskType, long num, int param, boolean isAdd) {
        TaskAchieve taskAchieve = getMaxTaskAchieve(taskType, param);
        if (taskAchieve == null || num < 1) {// 未配置对应的主线任务
            return;
        }
        long taskId = getTaskId(taskType, param);
        long userId = userInfo.getId();
        UserTaskValue userTaskValue = getUserTaskValue(userId, taskAchieve);
        if (userTaskValue == null) {
            userTaskValue = new UserTaskValue();
            userTaskValue.putUserId(userId);
            userTaskValue.putTaskId(taskId);
            userTaskValue.putNum(num);
            userTaskValue.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userTaskValue, true);
        } else {
            long taskValue = getTaskValue(userTaskValue);
            if (taskValue >= taskAchieve.getNum()) {
                return;// 已达到最大值了，不需要再更新
            }
            if (isAdd) {//增量更新
                userTaskValue.addNum(num);
            } else {
                if (num <= taskValue)  {
                    return;
                } else {
                    userTaskValue.putNum(num);
                }
            }
            userTaskValue.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userTaskValue);
        }

        if (taskType == MainTaskConstant.TASK_TYPE_113 || taskType == MainTaskConstant.TASK_TYPE_144 || taskType == MainTaskConstant.TASK_TYPE_184 || taskType == MainTaskConstant.TASK_TYPE_141 || taskType == MainTaskConstant.TASK_TYPE_117) {
            IapManager.sendGrowFundRedPoint(userInfo, taskType, userTaskValue.getNum());// 基金奖励有新的可领取时。给玩家推送红点
        }
    }

    // task_type 和parm 组成唯一值1 task_type(3位) param(6位) 如1103105019  主线任务需要用到
    public static long getTaskId(int taskType, int param) {
        long ss = 1000 + taskType;// 1XXX
        long result = ss * 1000000 + param;
        return result;
    }

    // 某任务类型的进度值,是否在领取完奖励需要重置，这种task_type只能配置在主线任务。不能配置在成就等
    public static boolean isResetNumByTaskType(int taskType) {
        TaskType entity = getTaskType(taskType);
        if (entity != null && entity.getIsResetNum() == 1) {
            return true;// 需要重置
        } else {
            return false;
        }
    }

    // 获取成长基金对应的进度值
    public static long takeGrowthProgress(UserInfo userInfo, int taskType) {
        long progressNum = 0L;
        switch (taskType) {
            case MainTaskConstant.TASK_TYPE_113:
                progressNum = userInfo.getLevel();
                break;
            case MainTaskConstant.TASK_TYPE_184:
                UserPower userPower = GameUser.getUserPower(userInfo.getId());
                progressNum = userPower.countCurrentEarn();
                break;
            case MainTaskConstant.TASK_TYPE_144:
            case MainTaskConstant.TASK_TYPE_141:
            case MainTaskConstant.TASK_TYPE_117:
                progressNum = getTaskValue(userInfo.getId(), taskType, 0);
                break;
        }

        return progressNum;
    }

    // 荣誉奖励的红点
    public static boolean checkRedPointHonor(CSGameSystemRedPointResponse.Builder builder, UserInfo userInfo){
        JsonArray serverHonorType = new JsonArray();
        serverHonorType.add(MainTaskConstant.HONOR_TYPE_1);
        serverHonorType.add(MainTaskConstant.HONOR_TYPE_2);
        serverHonorType.add(MainTaskConstant.HONOR_TYPE_3);
        serverHonorType.add(MainTaskConstant.HONOR_TYPE_4);

        CsGameSystem.RedPoint_Honor.Builder redPointHonor = CsGameSystem.RedPoint_Honor.newBuilder();
        for (int i=0; i<serverHonorType.size(); i++) {
            int honorType = serverHonorType.getInteger(i);
            checkRedPointServerHonor(redPointHonor, userInfo, honorType);
        }
        checkRedPointSnatch(redPointHonor, userInfo);// 物资争夺红点

        if (redPointHonor.getServerHonorCount() > 0 || redPointHonor.getSnatch()) {
            builder.setHonor(redPointHonor);
            return true;
        } else {
            return false;
        }
    }

    // 是否有荣誉奖励未领取 全服
    public static void checkRedPointServerHonor(CsGameSystem.RedPoint_Honor.Builder redPointHonor, UserInfo userInfo, int honorType) {
        UserHonor userHonor = getUserHonor(userInfo.getId(), honorType);
        JsonArray jsonArray = userHonor == null ? new JsonArray() : userHonor.getGetRewardArray();//领取记录
        for (HonorReward honorReward : getHonorRewardMap().values()) {
            if (honorReward.getHonorType() == honorType)  {
                ServerHonor serverHonor = getServerHonor(userInfo.getServerId(), honorReward.takeHonorId());
                if (serverHonor != null && serverHonor.getUserId() > 0 && !Tool.isInList(jsonArray, honorReward.getId())) {
                    redPointHonor.addServerHonor(honorType);
                    return;
                }
            }
        }
    }

    // 物资争夺红点
    public static void checkRedPointSnatch(CsGameSystem.RedPoint_Honor.Builder redPointHonor, UserInfo userInfo) {
        int honorType = MainTaskConstant.HONOR_TYPE_101;
        UserHonor userHonor = getUserHonor(userInfo.getId(), honorType);
        if (userHonor == null) {
            return;
        }
        for (HonorReward honorReward : getHonorRewardMap().values()) {
            if (honorReward.getHonorType() == honorType && userHonor.getNum() >= honorReward.getNum() && !Tool.isInList(userHonor.getGetRewardArray(), honorReward.getId())) {
                redPointHonor.setSnatch(true);
                return;
            }
        }
    }

    // 判断某个任务是否已经完成，任务进度值达标
    public static boolean isTaskComplete(long userId, TaskAchieve taskAchieve) {
        if (taskAchieve == null) {
            return false;
        }
        if (getTaskValue(userId, taskAchieve) >= taskAchieve.getNum()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 城市升级时补发，补发未领取的城市任务奖励
     * @param pbUserData
     * @param userInfo
     * @param oldLevel 升级前的等级
     */
    public static void resendCityTaskReward(PBUserData.Builder pbUserData, UserInfo userInfo, int oldLevel) {
        UserExp userExp = GameDataManager.getUserExp(oldLevel);
        if (userExp == null || Tool.isEmpty(userExp.getNeedTask())) {
            return;
        }
        JsonArray jsonArray = CommonUtils.strToJsonArray(userExp.getNeedTask());
        for (int i=0; i<jsonArray.size(); i++) {
            int taskAchieveId = jsonArray.getInteger(i);// 任务id
            TaskAchieve taskAchieve = MainTaskManager.getTaskAchieve(taskAchieveId);
            if (taskAchieve == null || !taskAchieve.isCityTask()) {
                continue;
            }

            if (!MainTaskManager.isTaskComplete(userInfo.getId(), taskAchieve)) {
                continue;// 进度值不达标
            }
            UserCityTaskReward userCityTaskReward = MainTaskManager.getUserCityTaskReward(userInfo.getId(), taskAchieve.getTaskType());
            if (userCityTaskReward != null && Tool.isInList(userCityTaskReward.getGetRewardArray(), taskAchieveId)) {
                continue;// 重复领取
            }
            MainTaskManager.getCityTaskReward(pbUserData, userInfo, taskAchieve, userCityTaskReward, true);// 领取城市任务奖励，并记录领取记录
        }
    }

    // 城市中心升级时，自动领取都市等级福利的奖励
    public static void autoGetCityLevelReward(PBUserData.Builder pbUserData, UserInfo userInfo, int curLevel) {
        int taskGroupId = ActConstant.ACT_TASK_GROUP_ID_CITY;
        List<ActTask> list = ActDaysManager.getActTasksByGroupId(taskGroupId);// 所有的都市等级福利配置
        UserActTaskReward userActTaskReward = OnceActManager.getUserActTastReward(userInfo.getId(), taskGroupId);// 领取记录
        JsonArray jsonArray = userActTaskReward == null ? new JsonArray() : userActTaskReward.getRewardInfoArray();
        boolean isUpdate = false;
        for (ActTask actTask : list) {
            if (actTask.getNum1() <= curLevel && !Tool.isInList(jsonArray, actTask.getNum1())) {// 等级达标，且未领取
                RewardManager.addReward(userInfo, actTask.getRewardItemList(), pbUserData, LogType.ACT_CITY_LEVEL_REWARD);
                jsonArray.add(actTask.getNum1());
                isUpdate = true;
            }
        }
        if (isUpdate) {// 需要更新领取记录
            if (userActTaskReward == null) {
                userActTaskReward = new UserActTaskReward();
                userActTaskReward.putUserId(userInfo.getId());
                userActTaskReward.putTaskGroupId(taskGroupId);
                userActTaskReward.putRewardInfo(jsonArray.toString());
                userActTaskReward.doCreate();
                ProtoDataUtils.updatePBUserData(pbUserData, userActTaskReward, true);
            } else {
                userActTaskReward.putRewardInfo(jsonArray.toString());
                userActTaskReward.update();
                ProtoDataUtils.updatePBUserData(pbUserData, userActTaskReward);
            }
        }
    }

    // 领取城市任务奖励，并记录领取记录
    public static void getCityTaskReward(PBUserData.Builder pbUserData, UserInfo userInfo, TaskAchieve taskAchieve, UserCityTaskReward userCityTaskReward, boolean isResend) {
        long userId = userInfo.getId();
        RewardManager.addReward(userInfo, CommonUtils.takeReawrdItemFromStr(taskAchieve.getReward()), pbUserData, LogType.ACHIEVE_REWARD, isResend ? "resend" : "");

        if (userCityTaskReward == null) {
            userCityTaskReward = new UserCityTaskReward();
            userCityTaskReward.putUserId(userId);
            userCityTaskReward.putTaskId(taskAchieve.getTaskType());
            JsonArray jsonArray = new JsonArray().add(taskAchieve.getId());
            userCityTaskReward.putGetReward(jsonArray.toString());
            userCityTaskReward.doCreate();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityTaskReward, true);
        } else {
            JsonArray jsonArray = userCityTaskReward.getGetRewardArray();
            jsonArray.add(taskAchieve.getId());
            userCityTaskReward.putGetReward(jsonArray.toString());
            userCityTaskReward.update();
            ProtoDataUtils.updatePBUserData(pbUserData, userCityTaskReward);
        }
    }

    // 获取任务进度值
    public static long getTaskValue(UserTaskValue userTaskValue) {
        if (userTaskValue == null) {
            return 0L;
        } else {
            return userTaskValue.getNum();
        }
    }

    // 获取任务进度值
    public static long getTaskValue(long userId, int taskType, int param) {
        long taskId = MainTaskManager.getTaskId(taskType, param);
        UserTaskValue userTaskValue = MainTaskManager.getUserTaskValue(userId, taskId);
        return getTaskValue(userTaskValue);
    }

    // 获取任务进度值
    public static long getTaskValue(long userId, TaskAchieve taskAchieve) {
        if (taskAchieve == null) {
            return 0L;
        }
        return getTaskValue(userId, taskAchieve.getTaskType(), taskAchieve.getParam());
    }
}
